#!/usr/bin/env python
#* **********************************************************
#* FileName	: KTserver.py
#* Author	: wule
#* Email	: ghostwwl@gmail.com
#* Date		: 2013.7.2
#* Note		: inter face for Kyoto Tycoon(user rpc Protocol)
#* **********************************************************/

import re
import httplib
import types
import socket
import base64
from urllib import quote, unquote, urlencode
import simplejson
from phpserialize import serialize, unserialize


class KTserver(object):
	def __init__(self, host='192.168.2.8', port=8205):
		self._host = None
		self._port = None
		self._timeout = 3
		self._api_url = ''
		self._enctype = 2
		self.header = None
		self.mapload = False
		self.kt = None

		if host is not None: self._host = host
		if port is not None: self._port = port
		self._api_url = "/rpc/"

	def set_time_out(self, _time_out):
		self._timeout = _time_out if _time_out > 0 else self._timeout
		if self._timeout > 0:
			socket.setdefaulttimeout(self._timeout)

	def _encode(self, value):
		if self._encode == 0:
			return serialize(value)
		elif self._encode == 1:
			return simplejson.dumps(value)
		else: return value

	def _decode(self, value):
		if self._encode == 0:
			return unserialize(value)
		elif self._encode == 1:
			return simplejson.loads(value)
		else: return value

	def array2tsv(self, params):
		tsv = ''
		for k, v in params.items():
			tsv += '%s\t%s\n' % (base64.b64encode(k), base64.b64encode(str(v)))
		return tsv

	def mapload(data,colenc, decode):
		rdata = {}
		reobj = re.findall('lastid([0-9]*)[^0-9](.+)', data)
		if reobj:
			rdata['lastid'] = reobj[0]
			valueobj = re.findall('value(.+)', reobj[1])
			if valueobj:
				rdata['value'] = valueobj[0][0]
		return rdata

	def tsv2array(self, response, colenc='U', decode=False):
		if response:
			data = {}
			items = response.split('\n')
			for item in items:
				if not item:continue
				kv = item.split('\t')
				if len(kv) == 2:
					if kv[0] == 'ERROR': data['ERROR'] = kv[1]
					else:
						key = kv[0]
						if key.startswith('_'): key = key[1:]
						if colenc == 'U':
							if self.mapload:
								data[unquote(key)] = self.mapload(unquote(kv[1]), colenc, decode)
							else: data[unquote(key)] = unquote(kv[1])
						elif colenc == 'B':
							key = base64.b64decode(key)
							if key.startswith('_'): key = key[1:]
							if self.mapload:
								data[key] = self.mapload(base64.b64decode(kv[1]), colenc, decode)
							else:data[key] = base64.b64decode(kv[1])
						else:
							data[key] = kv[1]
						if 'value'== key or decode:
							data[ key ] = self._decode( data[ key ] )
			del item
			return data
		return False

	def interface_post(self, url, params, decode=False):
		try:
			if params:
				data = self.array2tsv(params)
			else: data = ''
			headers = {"Content-type": "text/tab-separated-values; colenc=B",
			           "Content-length": len(data)}
			conn = httplib.HTTPConnection(self._host, self._port)
			conn.request('POST', url, data, headers)
			httpres = conn.getresponse()
			status = httpres.status
			reason = httpres.reason
			body = httpres.read()
			if status in (200, 450, 400):
				colenc = 'Q'
				con_type = httpres.getheader('Content-Type', 'Q')
				if '=' in con_type:
					colenc = con_type.split('=')[-1]
				if httpres.will_close:conn.close()
				if status == 200 and not body: return True
				return self.tsv2array(body, colenc,decode)
			if httpres.will_close:conn.close()
			return False
		except Exception, e:
			return False
		return False

	def play_script(self, name, inmap):
		api = "%splay_script" % self._api_url
		params = {'name':name}
		for k,v in inmap.items():
			if (k == 'value'): params['_%s' % k] = self._encode(v)
			else: params['_%s' % k] = v
		return self.interface_post(api, params)


	def check(self, key, db=None):
		api = "%scheck" % self._api_url
		params = {}
		if key: params['key'] = key
		else: return False
		if db: params['DB'] = db
		return self.interface_post(api, params)

	def get_bulk(self, keys, db=None, decode=True):
		api = "%sget_bulk" % self._api_url
		params = {}
		if type(keys) in (types.ListType, types.TupleType):
			for k in keys:
				params['_%s' % k] = ''
		else: return False
		if db: params['DB'] = db
		return self.interface_post(api, params)
	
	def get(self, key, db=None):
		api = '%sget' % self._api_url
		params = {}
		if key: params['key'] = key
		else: return False
		if db: params['DB'] = db
		return self.interface_post(api, params)
	
	def remove(self, key, db=None):
		api = '%sremove' % self._api_url
		params = {}
		if key: params['key'] = key
		else: return False
		if db: params['DB'] = db
		return self.interface_post(api, params)
	
	def remove_bulk(self, keys, db=None, decode=True):
		api = '%sremove_bulk' % self._api_url
		params = {}
		if type(keys) in (types.ListType, types.TupleType):
			for k in keys:
				params['_%s' % k] = ''
		else: return False
		if db: params['DB'] = db
		return self.interface_post(api, params)
	
	def set(self, key, value, limittime=0, db=None):
		api = '%sset' % self._api_url
		params = {'key':key, 'value':self._encode(value)}
		if db: params['DB'] = db
		if limittime > 0:params['xt'] = limittime
		return self.interface_post(api, params)


	def set_bulk(self, keys, limittime=0, db=None):
		api = '%sset_bulk' % self._api_url
		params = {}
		if type(keys) == types.DictionaryType:
			for k,v in keys.items():
				params['_%s' % k] = self._encode(v)
		else:return False
		if db: params['DB'] = db
		if limittime > 0:params['xt'] = limittime
		return self.interface_post(api, params)
	
	# 此函数尽量不要用 很糟糕的情况下会引起ktserver服务器负载急剧飙升
	def match_regex(self, regex_str, max_num=10, db=None):
		api = '%smatch_regex' % self._api_url
		params = {'regex': regex_str, 'max': max_num}
		if db: params['DB'] = db
		return self.interface_post(api, params)

	def get2(self, key):
		api = "http://%s:%s/%s" % (self._host, str(self._port), str(key))
		result = urlopen(api)
		if result:
			r = result.read()
			if r: 
				result.close()
				return r
		return None
	
	def server_report(self):
		api = '%sreport' % self._api_url
		params = {}
		info = self.interface_post(api, params)
		if not info: return False
		if info.has_key('db_total_size'):
			info['db_total_size'] = self.file_size(info['db_total_size'])
		if info.has_key('sys_mem_total'):
			info['sys_mem_total'] = self.file_size(info['sys_mem_total'])
		if info.has_key('sys_mem_peak'):
			info['sys_mem_peak'] = self.file_size(info['sys_mem_peak'])
		if info.has_key('sys_mem_free'):
			info['sys_mem_free'] = self.file_size(info['sys_mem_free'])
		if info.has_key('sys_mem_size'):
			info['sys_mem_size'] = self.file_size(info['sys_mem_size'])
			
		return info
	
	def file_size(self, sizes):
		sizes = int(sizes)
		info = ''
		if sizes > 1073741824: info = '%s G' % str(round(sizes / 1073741824 * 100.0, 2) / 100)
		elif sizes > 1048576: info = '%s M' % str(round(sizes / 1048576 * 100.0, 2) / 100)
		elif sizes > 1024: info = '%s K' % str(round(sizes / 1024 * 100.0, 2) / 100)
		else: info = '%s B' % str(sizes)
		return info
	
	def get_serverinfo(self):
		api = '%sstatus' % self._api_url
		params = {}
		info = self.interface_post(api, params)
		if not info: return False
		if info.has_key('size'):
			info['size'] = self.file_size(info['size'])
		if info.has_key('msiz'):
			info['msiz'] = self.file_size(info['msiz'])
		if info.has_key('realsize'):
			info['realsize'] = self.file_size(info['realsize'])
		return info
	

if __name__ == '__main__':
	print serialize({'file_link':'qwerqwerasdfasdfasdfsd_200'})
	
	T = KTserver('192.168.2.146', 11206)
	#d = T.set('ghostwwl', 'hahaha23h123a', 3600)
	#d = T.get('2fcfeae81d9dbb7b23f5d0abc233fddf_400')
	#d = T.get('http://shop.artxun.com/data/files/old_shop/200808/27/87b28fe3e1a6295b5a165de199fba009.jpg')
	#d = T.check('6f182ffc5f98f2dc83bc6c171bef6bbd_old')
	#d = T.set_bulk({'ghostwwl':'也是好东西', 'artxun':'好东西'}, 3600)
	#d = T.get_bulk(('ghostwwl', 'artxun'))
	#d = T.get('6f182ffc5f98f2dc83bc6c171bef6bbd_old')
	#d = T.server_report()
	print d
	for k, v in d.items():
		print "%s => %s" % (k,v)
	#d = T.server_report()
	#print d
	#d = unserialize(d['value'])
	#f = open('r:/pyt.jpg', 'wb')
	#f.write(d['file_content'])
	#f.close()
